#include "lcd.h"
#include "prospeckz.h"
#include "StopAndWait.h"
#include "xlowpan.h"
#include "MAC.h"
#include "bitmap.h"
#include "defines.h"
#include "game.h"
#include "scheduler.h"

#define MODE_GAME 0
#define MODE_END 1
#define MODE_SENDING 2 //sending a packet
#define MODE_SENT 3 //packet was sent, waiting for other player
#define MODE_EVAL 4 //both packets received, next loop iteration will recalculate scores
#define MODE_WAITING_FOR_YOU 5 //opponent's packet received, just waiting for current player to finish
#define MODE_FACEBOOK_Q 6 //game asks the user if they want to share the result at the end
#define MODE_OPP_ENDED 7 //other user has ended the game, inform the current user about that
#define MODE_RESULT_NOTIFICATION 8 //game notifies the user who won the last round in these modes

#define ROCK 0
#define PAPER 1
#define SCISSORS 2
#define END_GAME 3


extern struct xlowpan_addr64 BaseAddr;
extern struct xlowpan_addr64 MyAddr;
extern struct xlowpan_addr64 TargetAddr;



//item selection:
int item = ROCK;
int previous_item = ROCK;
int opponent_item = 0;
//scores:
int my_score = 0;
int their_score = 0;
int prev_my_score = 0;
int prev_their_score = 0;
//game mode:
int mode = MODE_GAME;
int bg_mode = MODE_GAME; //switch game state in "background" in case the game was in notification mode
int prev_mode = -1;
//buttons state:
int pressed = 0;


//strings:
const char rock_str[]      = "Rock    ";
const char paper_str[]     = "Paper   ";
const char scissors_str[]  = "Scissors";
const char end_game_str[]  = "END GAME";
const char draw_str[]      = "A draw";
const char win_str[]       = "You won.";
const char lose_str[]      = "You lost.";

void game_switch_mode(int new_mode)
{
	//switches game state if the game is not in notification state, otherwise it just switches the mode that the game can switch back to
	bg_mode = new_mode;
	if (mode != MODE_END && mode != MODE_RESULT_NOTIFICATION)
		mode = new_mode;
}

void game_switch_back_from_notification(int new_mode)
{
	//if the mode hasn't changed while the notification was being displayed it is switched to new_mode
	if (bg_mode!=new_mode)
		mode = bg_mode;
	else
		mode = new_mode;
}

void game_scroll_through_items_right(void)
{
	item += 1;
	if (item > 3)
		item = 0;
}

void game_scroll_through_items_left(void)
{
	item -= 1;
	if (item < 0)
		item = 3;
}

void game_update_screen(void)
{
	if (item != previous_item)
	{
		//
		if (item==ROCK)
		{
			lcd_print_rle_bitmap_pos(RockImage, 0,1);
			lcd_set_pos(5,0);
			lcd_print_cstring(rock_str);
		}
		if (item==PAPER)
		{
			lcd_print_rle_bitmap_pos(PaperImage, 0,1);
			lcd_set_pos(5,0);
			lcd_print_cstring(paper_str);
		}
		if (item==SCISSORS)
		{
			lcd_print_rle_bitmap_pos(ScissorsImage, 0,1);
			lcd_set_pos(5,0);
			lcd_print_cstring(scissors_str);
		}
		if (item==END_GAME)
		{
			lcd_print_rle_bitmap_pos(ExitImage, 0,1);
			lcd_set_pos(5,0);
			lcd_print_cstring(end_game_str);
		}
		previous_item = item;
	}
	if (prev_my_score != my_score || prev_their_score != their_score)
	{
		char my_buffer[3];
		char their_buffer[3];
		utoa(my_buffer, my_score, 10);
		utoa(their_buffer, their_score, 10);
		lcd_set_pos(0,0);
		lcd_print_cstring("Us: ");
		lcd_print_string(my_buffer);
		lcd_print_char(' ');
		lcd_print_cstring("Them: ");
		lcd_print_string(their_buffer);
		lcd_print_char(' ');
		lcd_print_char(' ');
		prev_my_score = my_score;
		prev_their_score = their_score;
	}
}

void game_initialise_screen(void)
{
	char my_buffer[5];
	char their_buffer[5];
	lcd_clear();
	if (item==ROCK)
	{
		lcd_print_rle_bitmap_pos(RockImage, 0,1);
		lcd_set_pos(5,0);
		lcd_print_cstring(rock_str);
	}
	if (item==PAPER)
	{
		lcd_print_rle_bitmap_pos(PaperImage, 0,1);
		lcd_set_pos(5,0);
		lcd_print_cstring(paper_str);
	}
	if (item==SCISSORS)
	{
		lcd_print_rle_bitmap_pos(ScissorsImage, 0,1);
		lcd_set_pos(5,0);
		lcd_print_cstring(scissors_str);
	}
	if (item==END_GAME)
	{
		lcd_print_rle_bitmap_pos(ExitImage, 0,1);
		lcd_set_pos(5,0);
		lcd_print_cstring(end_game_str);
	}
	lcd_set_pos(0,0);
	//lcd_print_full_bitmap(Game_r);
	utoa(my_buffer, my_score, 10);
	utoa(their_buffer, their_score, 10);
	lcd_print_cstring("Us: ");
	lcd_print_string(my_buffer);
	lcd_print_char(' ');
	lcd_print_cstring("Them: ");
	lcd_print_string(their_buffer);
	lcd_set_pos(5,0);
	lcd_print_cstring(rock_str);
	lcd_set_pos(7,0);
	lcd_print_cstring("<Prev OK Next>");
}

/**
 *Packet receive handler
 */
void game_receive_handler(struct xlowpan_addr64 *from, unsigned char* data, unsigned char hops, unsigned int length)
{
	char buffer[2];
	utoa(buffer, mode, 10);
	LED_Off;
	LED_BLUE_On;
	opponent_item = data[0];
	lcd_set_pos(6,3);
	lcd_print_string(buffer);
	if (mode==MODE_SENT || opponent_item == END_GAME)
	{
		game_switch_mode(MODE_EVAL);
	}
	else if(mode==MODE_GAME)
	{
		game_switch_mode(MODE_WAITING_FOR_YOU);
	}
	sched_addLowPriorityTask(&gameMainTask);
	
}

void game_process_selection(struct xlowpan_addr64 *opponent_addr)
{
	if (item >= 0 && item <=2)
	{
		unsigned char packet[2];
		int prev_mode = mode;
		packet[0] = item;
		packet[1] = 1;
		mode = MODE_SENDING;
		LED_Off;
		LED_BLUE_On;
		//send stuff
		//while (Reliable_TransmitPacket(opponent_addr,packet,2, 100000, 10)) {}
		//if (prev_mode==MODE_GAME) mode = MODE_SENT;
		//if (prev_mode==MODE_WAITING_FOR_YOU) mode = MODE_EVAL;
		if(!Reliable_TransmitPacket(opponent_addr,packet,2, 65000, 40))
		{
			//sent
			if (prev_mode==MODE_GAME)
			{
				lcd_clear();
				lcd_set_pos(0,0);
				lcd_print_cstring("Waiting for");
				lcd_set_pos(1,0);
				lcd_print_cstring("other user...");
				mode = MODE_SENT;
			}
			if (prev_mode==MODE_WAITING_FOR_YOU) mode = MODE_EVAL;
			LED_Off;
			LED_GREEN_On;
		}
		else
		{
			//fail
			if (prev_mode==MODE_GAME)
			{
				lcd_clear();
				lcd_set_pos(0,0);
				lcd_print_cstring("Waiting for");
				lcd_set_pos(1,0);
				lcd_print_cstring("other user...FAIL");
				lcd_set_pos(7,0);
				mode = MODE_SENT;
			}
			if (prev_mode==MODE_WAITING_FOR_YOU) mode = MODE_EVAL;
			LED_Off;
			LED_RED_On;
		}
	}
	if (item==3)
	{
		lcd_clear();
		lcd_set_pos(0,0);
		lcd_print_cstring("Are you sure?");
		lcd_set_pos(7,0);
		lcd_print_cstring("       No   Yes");
		mode = MODE_END;
	}
}

void game_result_notification(const char * str)
{
	lcd_clear();
	lcd_set_pos(0,0);
	lcd_print_cstring("Last round     ");
	lcd_set_pos(1,0);
	lcd_print_cstring("result:");
	lcd_set_pos(2,0);
	lcd_print_cstring(str);
	lcd_set_pos(7,0);
	lcd_print_cstring("       Ok      ");
	mode = MODE_RESULT_NOTIFICATION;
}

void game_eval(void)
{
	if (opponent_item==END_GAME)
	{
		lcd_clear();
		lcd_set_pos(0,0);
		lcd_print_cstring("Your opponent  ");
		lcd_set_pos(1,0);
		lcd_print_cstring("has ended the  ");
		lcd_set_pos(2,0);
		lcd_print_cstring("game.          ");
		lcd_set_pos(7,0);
		lcd_print_cstring("       Ok      ");
		mode = MODE_OPP_ENDED;
	}
	else
	{
		if (opponent_item==ROCK)
		{
			if (item==ROCK)
			{
				game_result_notification(draw_str);
			}
			if (item==PAPER)
			{
				game_result_notification(win_str);
				my_score += 1;
			}
			if (item==SCISSORS)
			{
				game_result_notification(lose_str);
				their_score += 1;
			}
		}
		else if (opponent_item==PAPER)
		{
			if (item==PAPER)
			{
				game_result_notification(draw_str);
			}
			if (item==SCISSORS)
			{
				game_result_notification(win_str);
				my_score += 1;
			}
			if (item==ROCK)
			{
				game_result_notification(lose_str);
				their_score += 1;
			}
		}
		else if (opponent_item==SCISSORS)
		{
			if (item==SCISSORS)
			{
				game_result_notification(draw_str);
			}
			if (item==ROCK)
			{
				game_result_notification(win_str);
				my_score += 1;
			}
			if (item==PAPER)
			{
				game_result_notification(lose_str);
				their_score += 1;
			}
		}
	}
}

void game_go_to_fb_mode(void)
{
	lcd_clear();
	lcd_set_pos(0,0);
	if (my_score > their_score)
		lcd_print_cstring("You won.");
	if (my_score < their_score)
		lcd_print_cstring("You lost.");
	if (my_score == their_score)
		lcd_print_cstring("It was a draw");
	lcd_set_pos(1,0);
	lcd_print_cstring("Would you like ");
	lcd_set_pos(2,0);
	lcd_print_cstring("to publish this");
	lcd_set_pos(3,0);
	lcd_print_cstring("story on");
	lcd_set_pos(4,0);
	lcd_print_cstring("Facebook?");
	lcd_set_pos(7,0);
	lcd_print_cstring("       No   Yes");
	mode = MODE_FACEBOOK_Q;
}

void sched_game_main(void)
{
	game_main();
	if (mode==MODE_EVAL)
	{
		game_eval();
	}
	else if (mode==MODE_GAME || mode == MODE_WAITING_FOR_YOU)
	{
		game_update_screen();
	}
	
}

/**
 *Main game procedure, call it every time in the main loop
 *@param B0 - state of the left button
 *@param B1 - state of the middle button
 *@param B2 - state of the right button
 *@parm opponent_addr - game opponent's address
 *
 *@return 1 if the game is still playing, 0 if it's finished
 */
void game_main(void)
{
	char buffer[3];
	struct xlowpan_addr64 *opponent_addr = &TargetAddr;
	struct xlowpan_addr64 *base_addr = &BaseAddr;
	utoa(buffer, mode, 10);
	lcd_set_pos(6,0);
	lcd_print_string(buffer);
	

	

	
	if( (testScheduleFlag(BUTTON_0_FLAG)) && !pressed)
	{
		pressed = 1;
		sched_unsetScheduleFlag(BUTTON_0_FLAG)
		if (mode==MODE_GAME || mode==MODE_WAITING_FOR_YOU)
			game_scroll_through_items_right();
		else if (mode==MODE_END)
		{
			unsigned char packet[2];
			packet[0] = END_GAME;
			packet[1] = 1;
			Reliable_TransmitPacket(opponent_addr,packet,2, 65000, 40);
			//ask about facebook
			game_go_to_fb_mode();
		}
		else if (mode==MODE_FACEBOOK_Q)
		{
			unsigned char packet[2];
			if (my_score > their_score)
				packet[0] = 'a';
			if (my_score < their_score)
				packet[0] = 'c';
			if (my_score == their_score)
				packet[0] = 'b';
			packet[1] = 'd';
			Reliable_TransmitPacket(base_addr,packet,2, 65000, 40);
			pressed = 0;
			return;
		}
		
	}
	if( (testScheduleFlag(BUTTON_2_FLAG)) && !pressed)
	{
		pressed = 1;
		sched_unsetScheduleFlag(BUTTON_2_FLAG)
		if (mode==MODE_GAME || mode==MODE_WAITING_FOR_YOU)
		{
			game_scroll_through_items_left();
		}
		
	}
	if( (testScheduleFlag(BUTTON_1_FLAG)) && !pressed)
	{
		pressed = 1;
		sched_unsetScheduleFlag(BUTTON_1_FLAG)
		if (mode==MODE_END)
		{
			//cancel ending
			lcd_clear();
			game_initialise_screen();
			item = ROCK;
			game_switch_back_from_notification(MODE_GAME);
		}
		else if (mode==MODE_GAME || mode==MODE_WAITING_FOR_YOU)
		{
			game_process_selection(opponent_addr);
		}
		else if (mode==MODE_FACEBOOK_Q)
		{
			//user decided not to publish a story, end and send result to the base
			unsigned char packet[2];
			if (my_score > their_score)
				packet[0] = 'a';
			if (my_score < their_score)
				packet[0] = 'c';
			if (my_score == their_score)
				packet[0] = 'b';
			packet[1] = 'e';
			Reliable_TransmitPacket(base_addr,packet,2, 65000, 40);
			pressed = 0;
			return;
			pressed = 0;
			return;
		}
		else if (mode==MODE_OPP_ENDED)
		{
			//close the warning and ask about facebook
			game_go_to_fb_mode();
		}
		else if (mode==MODE_RESULT_NOTIFICATION)
		{
			mode = MODE_GAME;
			//game_switch_back_from_notification(MODE_GAME);
			game_initialise_screen();
		}
	}
		
	if(pressed && !(testScheduleFlag(BUTTON_1_FLAG)) && !(testScheduleFlag(BUTTON_1_FLAG)) && !(testScheduleFlag(BUTTON_1_FLAG)) ) 
	{
		pressed = 0;
	}
	
	//sched_addLowPriorityTask(&gameMainTask);
	return;
}